#include "thread_pool.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

/*******************************************************
函数: int init_thread_pool(int max_count)
功能: 初始化线程池
参数: 线程池 最大线程数量
返回值: 失败返回非0 成功返回0
********************************************************/
int init_thread_pool(threadpool_t *pool, int max_count)
{

    // 初始化线程锁
    if (pthread_mutex_init(&pool->mutex, NULL))
    {
        perror("pool pthread_mutex_init");
        return -1;
    }
    // 初始化条件变量
    if (pthread_cond_init(&pool->cond, NULL))
    {
        perror("pool pthread_cond_init");
        return -1;
    }

    pool->first = NULL;
    pool->last = NULL;
    pool->counter = 0;
    pool->idel = 0;
    pool->max_count = max_count;
    pool->quit = 0; // 0 线程池正常 1 线程池关闭
    return 0;
}

/***********************************************************************************************
函数: void threadpool_add_task(threadpool_t *threadpool, void *(*func)(void *), void *arg)
功能: 线程池添加任务
参数: 线程池结构体 回调函数 回调函数参数
返回值: 无
************************************************************************************************/
void threadpool_add_task(threadpool_t *threadpool, void *(*func)(void *), void *arg)
{
    if(threadpool->quit) // 如果线程池关闭则不能加入任务
    {
        printf("threadpool closed\n");
        return;
    }
    task_t *task = malloc(sizeof(task_t));
    if (task == NULL)
    {
        perror("task malloc");
        return;
    }
    
    // 构建任务
    task->func = func;
    task->arg = arg;
    task->next = NULL;
    // 上锁
    pthread_mutex_lock(&threadpool->mutex);
    // 添加任务
    if (threadpool->first == NULL)

        threadpool->first = task;
    else
        threadpool->last->next = task;

    threadpool->last = task;
    // 如果有空闲线程唤醒
    if (threadpool->idel > 0)
    {
        pthread_cond_signal(&threadpool->cond);
    }
    else if (threadpool->counter < threadpool->max_count) // 如果当前线程数小于最大线程数可以创建新线程
    {
        pthread_t tid;
        pthread_create(&tid, NULL, thread_run, (void*)threadpool);
        threadpool->counter++; // 创建的线程数+1
    }

    // 解锁
    pthread_mutex_unlock(&threadpool->mutex);
}
/*******************************************************
函数: void* thread_run(void* arg)
功能: 执行线程任务函数
参数: 线程池结构体
返回值: 无
********************************************************/
void* thread_run(void* arg)
{
    struct timespec abstime; // 设置条件等待时间
    int timeout; // 超时标记

    threadpool_t* pool = (threadpool_t*)arg;
    while(1)
    {
        timeout = 0; // 设置成未超时
        pthread_mutex_lock(&pool->mutex);
        pool->idel++; // 空闲线程 +1
        // 当没有任务 并且 没有通知线程退出 时等待任务
        while(pool->first == NULL && !pool->quit) 
        {
            clock_gettime(CLOCK_REALTIME, &abstime); // 初始化时间
            abstime.tv_sec += 2; // 设置超时时间 2秒
            int status = pthread_cond_timedwait(&pool->cond, &pool->mutex, &abstime); // 设置条件变量等待时间
            if(status == ETIMEDOUT) // 如果是超时了就退出线程
            {
                timeout = 1;
                break;
            }
        }

        // 有任务时
        pool->idel--; // 空闲线程 -1
        if(pool->first != NULL)
        {
            task_t* task = pool->first; // 取出当前任务
            pool->first = task->next; // 更新待处理任务链表
            // 处理任务时需要解锁
            pthread_mutex_unlock(&pool->mutex);
            task->func(task->arg);
            free(task); // 任务执行完释放空间
            // 继续上锁
            pthread_mutex_lock(&pool->mutex);
        }

        // 线程销毁时
        if(pool->first == NULL && pool->quit)
        {
            pool->counter--; // 线程数量-1
            if(pool->counter == 0)
            {
                // 最后一个线程结束后通知收尾
                pthread_cond_signal(&pool->cond);
            }
            pthread_mutex_unlock(&pool->mutex);
            break;
        }

        // 超时情况
        if(pool->first == NULL && timeout)
        {
            pool->counter--; // 线程数量-1
            pthread_mutex_unlock(&pool->mutex);
            break;
        }

        pthread_mutex_unlock(&pool->mutex);
    }
}
/*******************************************************
函数: void threadpool_destory(threadpool_t* pool)
功能: 销毁线程池中的线程
参数: 线程池结构体
返回值: 无
********************************************************/
void threadpool_destory(threadpool_t* pool)
{
    // 如果线程池已经发起销毁了
    if(pool->quit)
    {
        return;
    }
    pthread_mutex_lock(&pool->mutex); // 上锁通知线程逐步关闭
    pool->quit = 1; // 设置线程池销毁标记
        if(pool->counter >0) // 还有存活线程的情况
        {
            if (pool->idel > 0) // 如果有空闲线程
                pthread_cond_broadcast(&pool->cond); // 通知空闲线程退出
            while(pool->counter > 0)
            {
                pthread_cond_wait(&pool->cond, &pool->mutex); // 等待线程退出
            }
        }
    pthread_mutex_unlock(&pool->mutex);
    pthread_mutex_destroy(&pool->mutex); // 销毁锁
    pthread_cond_destroy(&pool->cond); // 销毁条件变量
}